/******************************************************************************
 * vrtwarpedoverview.cpp
 *
 * Project:  Virtual GDAL Datasets
 * Purpose:  Implementation of VRTWarpedOverviewDataset.
 * Author:   Dmitry Barishnikov (Bishop) <polimax@mail.ru>
 *
 ******************************************************************************
 * Copyright (c) 2010, Dmitry Barishnikov (Bishop) <polimax@mail.ru>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 ****************************************************************************/
 
 #include "vrtwarpedoverview.h"
 
VRTWarpedOverviewDataset::VRTWarpedOverviewDataset(GDALDataset* pOverviewDS, GDALDataset* pParentDS) : m_pInternalDS(NULL), bGeoTransformValid(FALSE), nGCPCount(0), pszProjection(NULL), pszGCPProjection(NULL), pasGCPList(NULL)
{
    nRasterXSize = pOverviewDS->GetRasterXSize();
    nRasterYSize = pOverviewDS->GetRasterYSize();
    //nBands = pOverviewDS->GetRasterCount();
    for(int i = 0; i < pOverviewDS->GetRasterCount(); i++)
        SetBand(i + 1, pOverviewDS->GetRasterBand(i + 1));
	if(VRTWarpedOverviewDataset::SetProjection(pParentDS->GetProjectionRef()) != CE_None)
		return;
	// some transform
	if(pParentDS->GetGeoTransform(adfGeoTransform) == CE_None)
        bGeoTransformValid = TRUE;
    //else
	    //adfGeoTransform[1] = adfGeoTransform[1] * pOverviewDS->GetRasterXSize() / pParentDS->GetRasterXSize();
	    //adfGeoTransform[5] = adfGeoTransform[5] * pOverviewDS->GetRasterYSize() / pParentDS->GetRasterYSize();
        //adfGeoTransform = { 0.0, 1.0, 0.0, 0.0, 0.0, 1.0 };

	// need some transform	
	const char *pszGCPProjectionTmp = pParentDS->GetGCPProjection();
	int nGCPCountTmp = pParentDS->GetGCPCount();
	const GDAL_GCP *pasGCPListTmp = pParentDS->GetGCPs();
	if(VRTWarpedOverviewDataset::SetGCPs(nGCPCountTmp, pasGCPListTmp, pszGCPProjectionTmp) != CE_None)
		return;
	m_pInternalDS = pOverviewDS;	
}

VRTWarpedOverviewDataset::~VRTWarpedOverviewDataset(void)
{
    if( nGCPCount > 0 )
    {
        GDALDeinitGCPs( nGCPCount, pasGCPList );
        CPLFree( pasGCPList );
    }

    CPLFree( pszProjection );
	CPLFree( pszGCPProjection );

    CPLFree( papoBands );
    nBands = 0;
    papoBands = NULL;
}

GDALRasterBand *VRTWarpedOverviewDataset::GetRasterBand( int nBand)
{
	if(m_pInternalDS)
		return m_pInternalDS->GetRasterBand(nBand);
	return NULL;
}

const char *VRTWarpedOverviewDataset::GetProjectionRef(void)
{
    return pszProjection;
}

CPLErr VRTWarpedOverviewDataset::SetProjection( const char * pszNewProjection)
{
    if( !EQUALN(pszNewProjection,"GEOGCS",6)
        && !EQUALN(pszNewProjection,"PROJCS",6)
        && !EQUALN(pszNewProjection,"LOCAL_CS",6)
        && !EQUAL(pszNewProjection,"") )
    {
        CPLError( CE_Failure, CPLE_AppDefined, "Only OGC WKT Projections supported."
                "%s not supported.", pszNewProjection );        
        return CE_Failure;
    }
    
    CPLFree( pszProjection );
    pszProjection = CPLStrdup( pszNewProjection );

    return CE_None;
}

CPLErr VRTWarpedOverviewDataset::GetGeoTransform( double *padfTransform )
{
    memcpy( padfTransform, adfGeoTransform, sizeof(double) * 6 );
    
    if( !bGeoTransformValid )
        return CE_Failure;
    else
        return CE_None;
}

CPLErr VRTWarpedOverviewDataset::SetGeoTransform( double *padfTransform )
{
	memcpy( adfGeoTransform, padfTransform, sizeof(double) * 6 );
	bGeoTransformValid = TRUE;

	return( CE_None );
}

int VRTWarpedOverviewDataset::GetGCPCount()
{
    return nGCPCount;
}
const char *VRTWarpedOverviewDataset::GetGCPProjection()
{
    return pszGCPProjection;
}

const GDAL_GCP *VRTWarpedOverviewDataset::GetGCPs()
{
	return pasGCPList;
}

CPLErr VRTWarpedOverviewDataset::SetGCPs( int nGCPCount, const GDAL_GCP *pasGCPList, const char *pszGCPProjection )
{
	if( this->nGCPCount > 0 )
	{
		GDALDeinitGCPs( this->nGCPCount, this->pasGCPList );
		CPLFree( this->pasGCPList );
	}

	this->nGCPCount = nGCPCount;
	this->pasGCPList = GDALDuplicateGCPs(nGCPCount, pasGCPList);

    CPLFree( this->pszGCPProjection );
	this->pszGCPProjection = CPLStrdup( pszGCPProjection );

	return CE_None;
}

CPLErr VRTWarpedOverviewDataset::AdviseRead( int nXOff, int nYOff, int nXSize, int nYSize, int nBufXSize, int nBufYSize, GDALDataType eDT, int nBandCount, int *panBandList, char **papszOptions )
{
	if(m_pInternalDS)
		return m_pInternalDS->AdviseRead(nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize, eDT, nBandCount, panBandList, papszOptions);
	return CE_Failure;
}

CPLErr VRTWarpedOverviewDataset::CreateMaskBand( int nFlags )
{
	if(m_pInternalDS)
		return m_pInternalDS->CreateMaskBand(nFlags);
	return CE_Failure;
}
    
CPLErr  VRTWarpedOverviewDataset::RasterIO( GDALRWFlag eRWFlag, int nXOff, int nYOff, int nXSize, int nYSize, void * pData, int nBufXSize, int nBufYSize, GDALDataType eBufType,int nBandCount, int *panBandMap, int nPixelSpace, int nLineSpace, int nBandSpace )
{
	if(m_pInternalDS)
		return m_pInternalDS->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize, eBufType, nBandCount, panBandMap, nPixelSpace, nLineSpace, nBandSpace);
	return CE_Failure;
}
